Depth Stencil 버퍼를 읽을 수 있는 셰이더 리소스로 사용하기

텍스처를 셰이더에서 읽을땐 SRV에 묶을 필요가 있다
하지만 뎁스 스텐실에서 사용하는 포맷인 DXGI_FORMAT_D24_UNORM_S8_UINT는 SRV에서 읽을 수 없다. 따라서 아래와 같이 해준다.

리소스 생성

리소스를 생성할때 D3D12_RESOURCE_DESC::FormatDXGI_FORMAT_R24G8_TYPELESS로 해준다. 즉 사용처가 정해지지 않았다고 선언하는 것이다.
주의할 점은 D3D12_CLEAR_VALUE::FormatDXGI_FORMAT_D24_UNORM_S8_UINT로 해주어야 정상적으로 ClearDepthStencil을 실행할 수 있다.

D3D12_RESOURCE_DESC DepthStencilDesc;
ZeroMemory(&DepthStencilDesc, sizeof(D3D12_RESOURCE_DESC));
DepthStencilDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
DepthStencilDesc.Alignment = 0;
DepthStencilDesc.Width = mWidth;
DepthStencilDesc.Height = mHeight;
DepthStencilDesc.DepthOrArraySize = 1;
DepthStencilDesc.MipLevels = 1;
DepthStencilDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
DepthStencilDesc.SampleDesc.Count = 1;
DepthStencilDesc.SampleDesc.Quality = 0;
DepthStencilDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
DepthStencilDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;

OptClear.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
OptClear.DepthStencil.Depth = 1.0f;
OptClear.DepthStencil.Stencil = 0;
std::unique_ptr<FTexture> Texture = std::make_unique<FTexture>();
mDepthStencilTexture = Texture.get();
Texture->Name = std::string("RenderTargetDepth_") + std::to_string(sRenderTargetCount);
THROW_IF_FAILED(
	Device->CreateCommittedResource(
		&DefaultHeapProperties,
		D3D12_HEAP_FLAG_NONE,
		&DepthStencilDesc,
		D3D12_RESOURCE_STATE_COMMON,
		&OptClear,
		IID_PPV_ARGS(Texture->Resource.GetAddressOf())
	)
);

DSV 생성

DSV를 생성할때에는 D3D12_CLEAR_VALUE::Format의 값과 같이 포맷을 설정해 준다.

D3D12_DEPTH_STENCIL_VIEW_DESC DepthStencilViewDesc;
ZeroMemory(&DepthStencilViewDesc, sizeof(D3D12_DEPTH_STENCIL_VIEW_DESC));
DepthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
DepthStencilViewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
DepthStencilViewDesc.Flags = D3D12_DSV_FLAG_NONE;
DepthStencilViewDesc.Texture2D.MipSlice = 0;

Device->CreateDepthStencilView(
	mDepthStencilTexture->Resource.Get(),
	&DepthStencilViewDesc,
	mDSVHeap->GetCPUDescriptorHandleForHeapStart()
);

여기까지 하면 뎁스 스텐실에 쓰는것은 문제 없다.

SRV 생성

이제 SRV를 생성할때는 포맷을 다르게 설정해 주어야 한다.
D3D12_SHADER_RESOURCE_VIEW_DESC::FormatDXGI_FORMAT_R24_UNORM_X8_TYPELESS로 해서 뎁스는 읽고, 스텐실은 읽지 못하게 해준다.

D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};
SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
SRVDesc.Texture2D.MostDetailedMip = 0;
SRVDesc.Texture2D.ResourceMinLODClamp = 0.0f;
ID3D12Resource* TextureBuffer = Texture->Resource.Get();
SRVDesc.Texture2D.MipLevels = TextureBuffer->GetDesc().MipLevels;
SRVDesc.Format =	;

GetDXResourceManagerPtr()->GetDevicePtr()->CreateShaderResourceView(
	TextureBuffer,
	&SRVDesc,
	GetTexture2DCPUDescriptorHandle(Texture->SRVHeapIndex)
);

이제 뎁스 스텐실의 뎁스를 읽을 수 있다.

DepthStencilTexture.Sample(gsamLinearWrap, Texc).r

위와 같이 r값을 읽어오면 된다.